package com.bugsnag.ohos;

import com.google.gson.stream.JsonReader;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Persists and loads a [Streamable] object to the file system. This is intended for use
 * primarily as a replacement for primitive value stores such as [SharedPreferences].
 * <p>
 * This class is made thread safe through the use of a [ReadWriteLock].
 *
 * @param <T>
 * @since 2021-07-05
 */
public class SynchronizedStreamableStore<T extends JsonStream.Streamable> {
    private File file;

    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    /**
     * constructor
     *
     * @param file
     */
    public SynchronizedStreamableStore(File file) {
        this.file = file;
    }

    /**
     * persist
     *
     * @param streamable
     * @throws IOException
     */
    public void persist(T streamable) throws IOException {
        lock.writeLock().lock();
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "UTF-8");
            BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter, 8 * 1024);
            streamable.toStream(new JsonStream(bufferedWriter));
        } finally {
            lock.writeLock().unlock();
        }
    }

    /**
     * load
     *
     * @param loadCallback
     * @return t
     * @throws FileNotFoundException
     * @throws UnsupportedEncodingException
     */
    public T load(LoadCallback<T> loadCallback) throws FileNotFoundException, UnsupportedEncodingException {
        lock.readLock().lock();
        FileInputStream fileInputStream = new FileInputStream(file);
        InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
        BufferedReader bufferedReader = new BufferedReader(inputStreamReader, 8 * 1024);
        if (loadCallback != null) {
            return loadCallback.onLoadCallback(new JsonReader(bufferedReader));
        }
        return null;
    }

    /**
     * LoadCallback
     *
     * @param <T>
     * @since 2021-07-27
     */
    interface LoadCallback<T> {
        /**
         * onLoadCallback
         *
         * @param jsonReader
         * @return
         */
        T onLoadCallback(JsonReader jsonReader);
    }
}
